#include<iostream>
#include<string.h>
#include<unistd.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<sys/epoll.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/wait.h>
using namespace std;
#define PORT 8111
#define MESSAGE_LEN 1024
#define MAX_EVENTS 20
#define TIMEOUT 500
#define MAX_PROCESS 5
int main(){
        int socket_fd,accept_fd;
        int ret=-1;
        int on=1;

        int flags=1;
        int epoll_fd;
        struct epoll_event ev;
        struct epoll_event events[MAX_EVENTS];
        int event_number;

	pid_t pid=-1;


        char in_buff[MESSAGE_LEN]={0,};
        struct sockaddr_in localaddr;
        struct sockaddr_in remoteaddr;
        int backlog=10;

        socket_fd=socket(AF_INET,SOCK_STREAM,0);// IPV4  TCP  0  create a socket
        if(socket_fd==-1){
                cout<<"failed to create socket!"<<endl;
                exit(-1);
        }
        flags=fcntl(socket_fd,F_GETFL,0);
        fcntl(socket_fd,F_SETFL,flags|O_NONBLOCK);

        ret=setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); //set socket option
        if(ret==-1){
                cout<<"failed to set socket option"<<endl;
        }

        localaddr.sin_family=AF_INET;
        localaddr.sin_port=PORT;
        localaddr.sin_addr.s_addr=INADDR_ANY;//INADDR_ANY==0
        bzero(&(localaddr.sin_zero),8);

        ret=bind(socket_fd,(struct sockaddr *)&localaddr,sizeof(struct sockaddr));
        if(ret==-1){
                cout<<"failed to bind addr and port!"<<endl;
                exit(-1);
        }

        ret=listen(socket_fd,backlog);
        if(ret==-1){
                cout<<"failed to listen!"<<endl;
                exit(-1);
        }        
	
	for(int i=0;i<MAX_PROCESS;i++){//create five subprocess to excute fllowing program
		if(pid!=0){
			pid=fork();
		}
	}
     if(pid==0){//each subprocess create a epoll and put client connection in epoll
	epoll_fd=epoll_create(256);//create a epoll
        ev.events=EPOLLIN;
        ev.data.fd=socket_fd;
        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,socket_fd,&ev);//    add listen_socket to epoll	
        for(;;){
             event_number=epoll_wait(epoll_fd,events,MAX_EVENTS,TIMEOUT);//the number of fd with event
             for(int i=0;i<event_number;i++){//handle fd which true happen event
                if(events[i].data.fd==socket_fd){//listen_socket
                        //create a new socket accept_fd   //accept an new client connection
                        socklen_t addr_len=sizeof(struct sockaddr_in);
                        accept_fd=accept(socket_fd,(struct sockaddr *) &remoteaddr,&addr_len);// socket  client_ipAddress

                        flags=fcntl(accept_fd,F_GETFL,0);
                        fcntl(accept_fd,F_SETFL,flags|O_NONBLOCK);//set socket to non-blocking in order to add it in epoll

                        ev.events=EPOLLIN | EPOLLET;
                        ev.data.fd=accept_fd;
                        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,accept_fd,&ev);//add accept_fd to epoll and be controlled by epoll
                }
                else if(events[i].events & EPOLLIN){//input event
                        //client send data   read the received data into the in_buff
                     do{
                         memset(in_buff,0,MESSAGE_LEN);
                         ret=recv(events[i].data.fd,(void *)in_buff,MESSAGE_LEN,0);
                         if(ret==0){
                                cout<<"client don't send data,disconnected"<<endl;
                                close(events[i].data.fd);
                         }
                         if(ret==MESSAGE_LEN){
                                cout<<"maybe have data to be handleed"<<endl;
                         }

                     }while(ret<0 && errno==EINTR);
                         if(ret<0){
                                switch(errno){
                                        case EAGAIN:
                                                break;
                                        default:
                                                break;
                                }

                         }
                         if(ret>0){
                                cout<<"recveived data is:"<<in_buff<<endl;
                                send(events[i].data.fd,(void*)in_buff,MESSAGE_LEN,0);
                         }
                }
             }
            // close(accept_fd);
        }
    
	cout<<"quit server..."<<endl;
        close(socket_fd);
    }else{ //pid!=0     wait all subprocess finished
		do{
			pid=waitpid(-1,NULL,0);
		}while(pid!=-1); //pid==-1 means all subprocess is finished and father_process can quit
	}
        return 0;
}
